package com.china.cnlongdb.plugin.sequence;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.china.cnlongdb.basic.constant.LongDbConstant;
import com.china.cnlongdb.basic.entity.matchingrule.MatchingField;
import com.china.cnlongdb.basic.entity.query.LongDbQuery;
import com.china.cnlongdb.basic.entity.query.LongDbWhere;
import com.china.cnlongdb.plugin.sequence.constant.SequenceConstant;
import com.china.cnlongdb.plugin.sequence.entity.LongdbSequenceEntity;
import com.china.cnlongdb.plugin.sequence.service.ILongdbSequence;
import com.china.cnlongdb.server.connect.LongDbConnect;

/**
 * 系统名称：LongdbSequence
 * 模块名称：
 * 模块描述：提供的通用工具表 - 序列操作表
 * 功能列表：
 * 模块作者：zouyong
 * 开发时间：2019年7月24日 上午10:50:51
 * 模块路径：com.china.cnlongdb.plugin.sequence.LongdbSequence
 */
public class LongdbSequence implements ILongdbSequence {

	private final Logger logger = (Logger) LoggerFactory.getLogger(LongdbSequence.class);
	
	// 数据库连接对象
	private LongDbConnect connect;
	public LongdbSequence(LongDbConnect connect) {
		this.connect = connect;
	}

	@Override
	public long getSequence(String seqName) {
		
		return getSequenceByStartIncrNumber(seqName, SequenceConstant.startNumber, SequenceConstant.incrNumber);
	}

	@Override
	public long getSequenceByIncrNumber(String seqName, int incrNumber) {

		return getSequenceByStartIncrNumber(seqName, SequenceConstant.startNumber, incrNumber);
	}

	@Override
	public long getSequenceByStartNumber(String seqName, int startNumber) {

		return getSequenceByStartIncrNumber(seqName, startNumber, SequenceConstant.incrNumber);
	}

	@Override
	public long getSequenceByStartIncrNumber(String seqName, int startNumber, int incrNumber) {
		if(null == connect) {
			throw new RuntimeException("未获取到数据库连接对象！");
		}
		if(StringUtils.isBlank(seqName)) {
			return 0;
		}
		// 通过序列名称获取序列数据
		LongdbSequenceEntity sequence = querySequenceBySeqName(seqName, startNumber, incrNumber);
		if(null != sequence) {
			return sequence.getSeqValue();
		}
		return 0;
	}

	/**
	 * 功能描述：通过序列名称获取序列数据
	 × 模块作者：ZOUYONG
	 × 开发时间：2019年7月24日 上午11:24:18
	 × 返回数据：LongdbSequenceEntity
	 */
	private LongdbSequenceEntity querySequenceBySeqName(String seqName, int startNumber, int incrNumber) {
		if(StringUtils.isBlank(seqName)) {
			return null;
		}
		synchronized (seqName) {
			LongDbQuery query = new LongDbQuery();
			query.setClassz(LongdbSequenceEntity.class);
			query.addLongDbWhere(LongDbWhere.where(SequenceConstant.seqName).is(seqName).tableMatching(true));
			LongdbSequenceEntity sequence = connect.getQueryOperator().findOne(query);
			if(null == sequence) {
				// 设置按字段分区规则
				setSequenceFieldMatching();
				sequence = new LongdbSequenceEntity();
				sequence.setSeqName(seqName);
				sequence.setSeqValue(startNumber+incrNumber);
				// 进行新增
				connect.getInsertOperator().insert(sequence, LongdbSequenceEntity.class.getName(), false);
			} else {
				sequence.setSeqValue(sequence.getSeqValue()+incrNumber);
				try {
					// 进行修改
					connect.getUpdateOperator().update(query, sequence);
				} catch (Exception e) {
					logger.error("修改序列表数据操作异常：{}", e.getMessage());
					throw new RuntimeException(e.getMessage());
				}
			}
			return sequence;
		}
	}

	/**
	 * 功能描述：设置按字段分区规则
	 × 模块作者：ZOUYONG
	 × 开发时间：2019年7月24日 下午1:32:00
	 × 返回数据：void
	 */
	private void setSequenceFieldMatching() {
		String tableName = LongdbSequenceEntity.class.getName();
		boolean isAdd = true;
		List<Object> mathcList = connect.getMatchingList();
		for (int i=0; i<mathcList.size(); i++) {
			Object matching = mathcList.get(i);
			if(matching instanceof MatchingField) {
				MatchingField field = (MatchingField) matching;
				if(null != field.getFieldMap().get(tableName) && 
						field.getFieldMap().get(tableName).size() > 0) {
					isAdd = false;
					break;
				}
			}
		}
		if(isAdd) {
			MatchingField field = new MatchingField();
			field.setRuleType(LongDbConstant.fieldMatching);
			List<String> fids = new ArrayList<String>();
			fids.add(SequenceConstant.seqName);
			field.getFieldMap().put(tableName, fids);
			connect.getMatchingList().add(field);
		}
	}

}
